/*
 * net_server.h
 *
 *  Created on: 2014-4-25
 *      Author: Kise
 */

#ifndef NET_SERVER_H_
#define NET_SERVER_H_

#include <pthread.h>
#include <sys/types.h>
#include <cm/struct/list.h>
#include "net_constant.h"
#include "net_session.h"

struct net_server {
	struct list_head list;

	/* 服务端的监听套接字 */
	int listen_fd;

	/* 已经连接到该服务端的会话的 头节点 */
	struct list_head sessions;

	//TODO 其他属性

	session_proc proc;

	/* 指定为连接上来的会话创建缓存的大小 */
	size_t rsize;
	size_t wsize;

	pthread_mutex_t lock;
};

static inline int lock_server(struct net_server *server)
{
	return (pthread_mutex_lock(&(server->lock)));
}

static inline int trylock_server(struct net_server *server)
{
	return (pthread_mutex_trylock(&(server->lock)));
}

static inline int unlock_server(struct net_server *server)
{
	return (pthread_mutex_unlock(&(server->lock)));
}

/*
 * @brief	创建一个服务端结构，在堆上分配空间
 * @param	fd是一个监听套接字， size指定为新会话创建多大的缓存
 * 		proc指定服务端的所有会话处理数据的回调函数
 * @return	描述服务端的结构体,失败返回NULL
 */
static inline struct net_server *server_new(int fd, size_t rsize, size_t wsize,
		session_proc proc)
{
	struct net_server *server = calloc(1, sizeof(struct net_server));
	if (server == NULL)
		return NULL;

	server->listen_fd = fd;
	server->proc = proc;
	server->rsize = rsize;
	server->wsize = wsize;

	init_list_head(&(server->list));
	init_list_head(&(server->sessions));

	pthread_mutex_init(&(server->lock), NULL);
	return server;
}

/*
 * @brief	删除服务端，停止监听，关闭所有链接，以及释放其所占用的所有空间
 */
static inline void server_delete(struct net_server **s)
{
	if (s == NULL || *s == NULL)
		return;

	release_mutex_t((*s)->lock);

	list_del(&((*s)->list));
	close((*s)->listen_fd);
	close_sessions(&((*s)->sessions));
	free(*s);
	*s = NULL;
}

/*
 * @brief	关闭一个服务端链表，链表head中的所有元素必须保证是struct net_server结构
 * @param	head是链表头而不是其中的一个元素
 */
static inline void close_servers(struct list_head *head)
{
	if (head == NULL)
		return;
	struct list_head *temp = NULL;
	struct list_head *safe;
	list_for_each_safe(temp, safe, head)
	{
		struct net_server *t = list_entry(temp, struct net_server,
				list);
		server_delete(&t);
	}
}

#endif /* NET_SERVER_H_ */
